package com.example.oss.Interceptor;


import com.alibaba.fastjson.JSON;
import com.example.oss.annotation.AccessLimit;
import com.example.oss.entity.Result;
import com.example.oss.entity.ResultEnum;
import com.example.oss.util.RedisKeyUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.util.concurrent.TimeUnit;


/**
 * 接口限流拦截器
 */
@Component
@RequiredArgsConstructor
@Slf4j
public class AccessLimitInterceptor implements HandlerInterceptor {


    private final RedisTemplate redisTemplate;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (handler instanceof HandlerMethod) {
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            AccessLimit accessLimit = handlerMethod.getMethodAnnotation(AccessLimit.class);
            if (accessLimit != null) {
                int maxCount = accessLimit.maxCount();

                //以请求的uri为key, 设定过期时间1分钟，
                String refreshLimitKey = RedisKeyUtil.getRefreshLimitKey(request.getRequestURI());

                Integer count = (Integer)redisTemplate.opsForValue().get(refreshLimitKey);
                if (count == null) redisTemplate.opsForValue().set(refreshLimitKey, 1, 60, TimeUnit.SECONDS);
                else if (count <= maxCount) redisTemplate.opsForValue().increment(refreshLimitKey);
                else {
                    String xRequestedWith = request.getHeader("x-requested-with");
                    if ("XMLHttpRequest".equals(xRequestedWith)) { //如果是异步请求，返回Json提示信息
                        response.setContentType("application/json");
                        response.setCharacterEncoding("UTF-8");
                        PrintWriter writer = response.getWriter();
                        writer.write(JSON.toJSONString(Result.failure(ResultEnum.LIMIT)));
                        writer.flush();
                        writer.close();
                    } else {  //同步则请求返回提示页面
                        response.sendRedirect(request.getContextPath() + "/401");
                    }
                    log.info("限流。。。。");
                    return false;
                }
            }
        }
        return true;
    }
}
